﻿using System;
using System.IO;
using System.IO.Compression;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 压缩解压
    /// </summary>
    public class CompressEx
    {
        /// <summary>
        /// 压缩字节数组
        /// </summary>
        /// <param name="inputData">待压缩字节数组</param>
        /// <returns>压缩后的字节数组</returns>
        public static byte[] CompressBytes(byte[] inputData)
        {
            using (MemoryStream outStream = new MemoryStream())
            {
                using (var zipStream = new GZipStream(outStream, CompressionMode.Compress, true))
                {
                    zipStream.Write(inputData, 0, inputData.Length);
                }
                return outStream.ToArray();
            }
        }

        /// <summary>
        /// 压缩字节数组
        /// </summary>
        /// <param name="inputData">待压缩字节数组</param>
        /// <param name="outStream">压缩后的字节数组</param>
        /// <returns>压缩后的字节长度</returns>
        public static long CompressBytes(Span<byte> inputData, Stream outStream)
        {
            using (var zipStream = new GZipStream(outStream, CompressionMode.Compress, true))
            {
                zipStream.Write(inputData);
            }
            return outStream.Position;
        }

        /// <summary>
        /// 解压缩字节数组
        /// </summary>
        /// <param name="inputData">待解压字节数组</param>
        /// <returns>解压后的字节数组</returns>
        public static byte[] DecompressBytes(byte[] inputData)
        {
            using (var inputStream = new MemoryStream(inputData))
            {
                using (var outStream = new MemoryStream())
                {
                    using (var zipStream = new GZipStream(inputStream, CompressionMode.Decompress))
                    {
                        zipStream.CopyTo(outStream);
                    }
                    return outStream.ToArray();
                }
            }
        }

        /// <summary>
        /// 解压缩字节数组
        /// </summary>
        /// <param name="inputStream">待解压数据流</param>
        /// <param name="outStream">存放解压后数据的流</param>
        /// <returns>解压缩后的字节长度</returns>
        unsafe public static long DecompressBytes(Stream inputStream, Stream outStream)
        {
            using (var zipStream = new GZipStream(inputStream, CompressionMode.Decompress))
            {
                zipStream.CopyTo(outStream);
            }
            return outStream.Position;
        }


        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="inputDir">待压缩的文件夹</param>
        /// <param name="outputFilePath">输出压缩文件路径</param>
        public static void CompressDir(string inputDir, string outputFilePath)
        {
            if (string.IsNullOrWhiteSpace(Path.GetPathRoot(inputDir)))
            {
                inputDir = Path.GetFullPath(inputDir);
            }

            string[] files = Directory.GetFiles(inputDir);
            using (var fs = new MemoryStream())
            {
                var writer = new BinaryWriter(fs);
                writer.Write(files.Length);

                for (int i = 0; i < files.Length; i++)
                {
                    //char[] fileName = Path.GetFileName(files[i]).ToCharArray();
                    char[] fileName = files[i].Substring(inputDir.Length).ToCharArray();
                    writer.Write(fileName.Length);
                    writer.Write(fileName);

                    byte[] buffer = File.ReadAllBytes(files[i]);
                    writer.Write(buffer.Length);
                    writer.Write(buffer);
                }

                byte[] data = CompressBytes(fs.ToArray());
                File.WriteAllBytes(outputFilePath, data);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="srcFile"></param>
        /// <param name="outputDir"></param>
        public static void DecompressDir(string srcFile, string outputDir)
        {
            byte[] buffer = DecompressBytes(File.ReadAllBytes(srcFile));
            using (var fs = new MemoryStream(buffer))
            {
                var reader = new BinaryReader(fs);
                int count = reader.ReadInt32();
                for (int i = 0; i < count; i++)
                {
                    int len = reader.ReadInt32();
                    string fileName = new string(reader.ReadChars(len));

                    len = reader.ReadInt32();
                    byte[] data = reader.ReadBytes(len);

                    string filePath = PathEx.Combine(PathType.Local, outputDir, fileName);
                    DirectoryInfoEx.CheckFilePathDirectory(filePath);
                    File.WriteAllBytes(filePath, data);
                }
            }
        }





        /// <summary>
        /// 压缩目录
        /// </summary>
        /// <param name="dir"></param>
        public static void CompressDir(DirectoryInfo dir)
        {
            foreach (FileInfo fileToCompress in dir.GetFiles())
            {
                CompressFile(fileToCompress);
            }
        }

        /// <summary>
        /// 解压缩目录
        /// </summary>
        /// <param name="dir"></param>
        public static void DecompressDir(DirectoryInfo dir)
        {
            foreach (FileInfo fileToCompress in dir.GetFiles())
            {
                DecompressFile(fileToCompress);
            }
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="fileToCompress"></param>
        public static void CompressFile(FileInfo fileToCompress)
        {
            using (FileStream originalFileStream = fileToCompress.OpenRead())
            {
                if ((File.GetAttributes(fileToCompress.FullName) & FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
                {
                    using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz"))
                    {
                        using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
                        {
                            originalFileStream.CopyTo(compressionStream);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="fileToDecompress"></param>
        public static void DecompressFile(FileInfo fileToDecompress)
        {
            using (FileStream originalFileStream = fileToDecompress.OpenRead())
            {
                string currentFileName = fileToDecompress.FullName;
                string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);
                using (FileStream decompressedFileStream = File.Create(newFileName))
                {
                    using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
                    {
                        decompressionStream.CopyTo(decompressedFileStream);
                    }
                }
            }
        }
    }
}
